/*
 * parser.c
 *
 *  Created on: 15/09/2010
 *      Author: dela
 */

#include "parser.h"
#include "listaAux.h"
#include "../domain/node.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <malloc.h>
#include <ctype.h>

#if !defined(FILM)
#define FILM "film"
#endif
#if !defined(FILM_END)
#define FILM_END "/film"
#endif
#if !defined(ID)
#define ID "id"
#endif
#if !defined(TITLE)
#define TITLE "title"
#endif
#if !defined(DIRECTOR)
#define DIRECTOR "director"
#endif
#if !defined(WRITER)
#define WRITER "writer"
#endif
#if !defined(ACTOR)
#define ACTOR "actor"
#endif

int getNextElem( FILE *file, char *buff, char *c );
int getText( FILE *file, char *text, char *c );
void decodeName( char **name );

/**
 *
 */
bool parser_getNextFilm( FILE *file, TFilm *film ) {
	bool filmFound = true;
	char *buff = malloc(15*sizeof(char));
	char *text = malloc(NAME_MAX_LENGTH*sizeof(char));
	char *c = malloc(sizeof(char));

	//Entro al siguiente film:
	do {
		if ( !getNextElem(file, buff, c) ) {
			filmFound = false;
		}
	} while ( strcmp(buff, FILM) != 0 && filmFound );

	if ( filmFound ) {
		memset( film, 0, sizeof(TFilm) );
		ls_Crear( &(film->people) );

		//Agrego la información a la pelicula:
		while(filmFound) {
			getNextElem(file, buff, c);
			if ( !strcmp(buff, FILM_END) )
				break;
			if ( !strcmp(buff, ID) ||
					!strcmp(buff, DIRECTOR) ||
					!strcmp(buff, WRITER) ||
					!strcmp(buff, ACTOR) ) {
				getText(file, text, c);
				//Si es el titulo:
				if ( !strcmp(buff, ID) ) {
					if ( !film->title ) {
						film->title = malloc( (strlen(text)+1)*sizeof(char) );
						strcpy(film->title, text);
						decodeName( &(film->title) );
					}
				}
				//Si es un una persona
				else {
					TPerson *person = malloc( sizeof(TPerson) );
					if ( !strcmp(buff, DIRECTOR) )
						person->type = TYPE_DIRECTOR;
					else if ( !strcmp(buff, WRITER) )
						person->type = TYPE_WRITER;
					else person->type = TYPE_ACTOR;
					person->name = malloc( (strlen(text)+1)*sizeof(char) );
					strcpy(person->name, text);
					decodeName( &(person->name) );

					//Agrego la persona a la lista:
					ls_Insertar( &(film->people), LS_PRIMERO, person);
				}
			}
		}
	}

	free(buff);
	free(text);
	free(c);
	return filmFound;
}

/**
 *
 */
void parser_buildStructData( TGraph *graph, TListaSimple *films, TListaSimple *people, int *peopleAmount ) {
	int fileStart = 0; //TODO tiene q ir en 0
	//Inicializo las listas:
	ls_Crear( people );
	ls_Crear( films );
	ls_Crear( &(graph->nodes) );
	*peopleAmount = 0;

	//Hago una primera pasada para generar las listas ordenadas:
	int i = fileStart;
	char *fileName = malloc( 25*sizeof(char) );
	sprintf(fileName,"%s%i%s",PATH_START,i,PATH_END);
	FILE *file = fopen( fileName, "r" );
	while (file) {
		printf("%s\n",fileName); //TODO borrar
		TFilm *film;
		film = malloc( sizeof(TFilm) );
		TPerson *person;
		while ( parser_getNextFilm(file, film) ) {
			char *filmName = malloc( (strlen(film->title)+1)*sizeof(char) );
			strcpy(filmName, film->title);
			if ( !lsAux_insertOrderString( films, filmName ) ) {
				free(filmName);
			} //else *filmsAmount++;
			if ( !ls_Vacia( film->people ) ) {
				ls_MoverCorriente( &(film->people), LS_PRIMERO );
				do {
					ls_ElemCorriente( film->people, (void**)&person );
					regPer *reg = malloc( sizeof(regPer) );
					reg->rubro = person->type;
					strcpy(reg->nombre, person->name);
					if ( !lsAux_insertOrderPerson( people, reg ) ) {
						free(reg);
					} else {
						(*peopleAmount)++;
					}
				} while ( ls_MoverCorriente( &(film->people), LS_SIGUIENTE ) );
			}
			film_destroy(film);
		}
		free(film);

		fclose(file);

		i++;
		sprintf(fileName,"%s%i%s",PATH_START,i,PATH_END);
		file = fopen( fileName, "r" );
	}

	//Hago una segunda pasada para generar el grafo:
	i = fileStart;
	sprintf(fileName,"%s%i%s",PATH_START,i,PATH_END);
	file = fopen( fileName, "r" );
	while (file) {
		printf("%s\n",fileName);
		TFilm *film;
		film = malloc( sizeof(TFilm) );
		while ( parser_getNextFilm(file, film) ) {
			//Creo el nodo de la pelicula:
			TNode *filmNode = malloc( sizeof(TNode) );
			filmNode->id = lsAux_getIdexOfString( films, film->title );
			filmNode->type = NODO_FILM;
			ls_Crear( &(filmNode->nodes) );
			ls_Crear( &(filmNode->ids) );
			ls_Insertar( &(graph->nodes), LS_PRIMERO, filmNode );
			if ( !ls_Vacia( film->people ) ) {
				ls_MoverCorriente( &(film->people), LS_PRIMERO );
				do {
					//Obtengo / Creo el nodo de la persona:
					TPerson *person;
					ls_ElemCorriente( film->people, (void**)&person );
					int personId = lsAux_getIdexOfPerson( people, person->name );
					TNode *personNode;
					graph_getPersonNode( graph, &personNode, personId );
					//Agrego nuevas relaciones:
					ls_Insertar( &(filmNode->nodes), LS_PRIMERO, personNode );
					ls_Insertar( &(personNode->nodes), LS_PRIMERO, filmNode );
				} while ( ls_MoverCorriente( &(film->people), LS_SIGUIENTE ) );
			}
			film_destroy(film);
		}
		free(film);

		fclose(file);

		i++;
		sprintf(fileName,"%s%i%s",PATH_START,i,PATH_END);
		file = fopen( fileName, "r" );
	}

	free(fileName);
}

/**
 *
 */
int getNextElem( FILE *file, char *buff, char *c ) {
	int i;
	*c = ' ';

	//Avanzo hasta el primer '<'
	while( *c != '<' && *c != EOF ) {
		*c = fgetc(file);
	}

	if ( *c == EOF ) {
		return false;
	}

	//Almaceno en buff hasta '>'
	i=0;
	*c = fgetc(file);
	do {
		buff[i] = *c;
		i++;
		*c = fgetc(file);
	} while( *c != '>' );
	buff[i] = '\0';
	return true;
}

/**
 *
 */
int getText( FILE *file, char *text, char *c ) {
	int i;

	//Almaceno hasta '<'
	i=0;
	*c = fgetc(file);
	while( *c != '<' && i < NAME_MAX_LENGTH-1) {
		text[i] = *c;
		i++;
		*c = fgetc(file);
	}
	text[i] = '\0';
	return true;
}

/**
 *
 */
void decodeName( char **name ) {
	char *nameAux = malloc( NAME_MAX_LENGTH*sizeof(char) );
	memset( nameAux, 0, NAME_MAX_LENGTH*sizeof(char) );

	//Apunto al nombre:
	char *aux = *name + sizeof(char)*28;

	//Cambio de caracteres:
	int i = 0;
	int k = 0;
	while ( i + k < strlen(aux) ) {
		if ( aux[i+k] == '_' ) {
			nameAux[i] = ' ';
		} else if ( aux[i+k] == '%' ) {
			k++;
			if ( aux[i+k] < '8' ) {
				//Es código de 1 byte.
				int c1 = aux[i+k]-48;
				int c2 = aux[i+k+1] < 58 ? aux[i+k+1]-48 : aux[i+k+1]-55;
				nameAux[i] = c1*16 + c2;
				k++;
			} else {
				//Es código de 2 bytes.
				int c2 = 0;
				int cAux;
				int c2Aux = aux[i+k+1] < 58 ? aux[i+k+1]-48 : aux[i+k+1]-55;
				int c3Aux = aux[i+k+3] < 58 ? aux[i+k+3]-48 : aux[i+k+3]-55;
				int c4Aux = aux[i+k+4] < 58 ? aux[i+k+4]-48 : aux[i+k+4]-55;

				c2 = c2Aux & 0x03;
				c2 = c2 << 6;
				cAux = c3Aux & 0x03;
				cAux = cAux << 4;
				c2 = c2 | cAux;
				c2 = c2 | c4Aux;

				if (c2 >= 224 && c2 <= 229) c2 = 97; //a
				else if (c2 >= 232 && c2 <= 235) c2 = 101; //e
				else if (c2 >= 236 && c2 <= 239) c2 = 105; //i
				else if (c2 >= 242 && c2 <= 246) c2 = 111; //o
				else if (c2 >= 249 && c2 <= 252) c2 = 117; //u
				else if (c2 >= 192 && c2 <= 197) c2 = 65; //A
				else if (c2 >= 200 && c2 <= 203) c2 = 69; //E
				else if (c2 >= 204 && c2 <= 207) c2 = 73; //I
				else if (c2 >= 210 && c2 <= 214) c2 = 79; //O
				else if (c2 >= 217 && c2 <= 220) c2 = 85; //U
				else if (c2 == 128) {c2 = 39;k=k+3;} //'
				else c2 = 42; //*

				nameAux[i] = c2;
				k=k+4;
			}
		} else {
			nameAux[i] = aux[i+k];
		}
		i++;
	}
	nameAux[i+1] = '\0';

	free( *name );
	*name = malloc( (strlen(nameAux)+1)*sizeof(char) );
	strcpy(*name, nameAux);

	free(nameAux);
}
